/* Includes ------------------------------------------------------------------*/
#include "stm32f0xx.h"
//#include "stdio.h"

//0x0000:0618a version only 1byte version
//0x0001:0806a version add 2btye version
#define BL_FW_VERSION	(0x0001)

//const char BlVer __attribute__((at(0x08000ffC))) = BL_FW_VERSION; /* RO */


//#define ENABLE_K6_PA15	(1)

#define PAGE_SIZE                         (0x400)
#define FLASH_SIZE                        (0x10000) /* 64 K */
#define TOTAL_PAGE_NUMBER    		    			((uint16_t)0x40)/* 64 PAGES */
//
#ifdef ENABLE_K6_PA15
#if(1)
//for 32KB 12KB+20KB
	#define LOADER_ADDRESS     								(uint32_t)(0x08000000)
	#define LOADER_ADDRESS_END     						(uint32_t)(0x08002FFF)
	#define APPLICATION_ADDRESS     					(uint32_t)(0x08003000)
	#define APPLICATION_ADDRESS_END 					(uint32_t)(0x08007FFF)
#else	
//for 16KB 4KB+12KB
	#define LOADER_ADDRESS     								(uint32_t)(0x08000000)
	#define LOADER_ADDRESS_END     						(uint32_t)(0x08000FFF)
	#define APPLICATION_ADDRESS     					(uint32_t)(0x08001000)
	#define APPLICATION_ADDRESS_END 					(uint32_t)(0x08003FFF)
#endif	
#else
//for 16KB 4KB+12KB
	#define LOADER_ADDRESS     								(uint32_t)(0x08000000)
	#define LOADER_ADDRESS_END     						(uint32_t)(0x08000FFF)
	#define APPLICATION_ADDRESS     					(uint32_t)(0x08001000)
	#define APPLICATION_ADDRESS_END 					(uint32_t)(0x08003FFF)
#endif


/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static __IO uint32_t TimingDelay;

#if(0)
int fputc(int ch, FILE *stream)
{
	
  USART_SendData(USART1, (uint8_t) ch);

  /* Loop until the end of transmission */
  while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
  {}

  return ch;	
}

int fgetc(FILE *f)
{
 
  /* Waiting for user input */
  while ( USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
  return USART_ReceiveData(USART1);
 
} 
#endif
char ChkUartRx(void)
{
	char tmp=0;//NULL byte
	
  /* Waiting for user input */
  if ( USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)
	{
		tmp=USART_ReceiveData(USART1);
	}
  if ( USART_GetFlagStatus(USART1, USART_FLAG_ORE) == SET)
	{
		tmp=USART_ReceiveData(USART1);
		USART_ClearFlag(USART1, USART_FLAG_ORE);
	}	

  if ( USART_GetFlagStatus(USART1, USART_FLAG_NE) == SET)
	{
		tmp=USART_ReceiveData(USART1);
		USART_ClearFlag(USART1, USART_FLAG_NE);
	}	
	
  if ( USART_GetFlagStatus(USART1, USART_FLAG_FE) == SET)
	{
		tmp=USART_ReceiveData(USART1);
		USART_ClearFlag(USART1, USART_FLAG_FE);
	}		
	 
  if ( USART_GetFlagStatus(USART1, USART_FLAG_PE) == SET)
	{
		tmp=USART_ReceiveData(USART1);
		USART_ClearFlag(USART1, USART_FLAG_PE);
	}		
	 	 
	return tmp;
	
}


__IO uint16_t NowCounter;
__IO uint16_t PreCounter;	
uint16_t GetAbsTime(uint16_t a,uint16_t b)
{
	uint16_t c;
	if(a>=b) c=(a-b);
	else c=65535-(b-a);	
	
	return c;
}
void UART_ConfigPA23(void)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
 
  USART_InitStructure.USART_BaudRate = 115200;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;


  /* Enable GPIO clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

  /* Enable USART clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); 

  /* Connect PXx to USARTx_Tx */
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_1);

  /* Connect PXx to USARTx_Rx */
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_1);
  
  /* Configure USART Tx as alternate function push-pull */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
    
  /* Configure USART Rx as alternate function push-pull */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* USART configuration */
  USART_Init(USART1, &USART_InitStructure);
    
  /* Enable USART */
  USART_Cmd(USART1, ENABLE);
}
void UartPutc(uint8_t ch)
{
  USART_SendData(USART1, (uint8_t) ch);

  /* Loop until transmit data register is empty */
  while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
  {}
}
void UartPuts(char* str)
{
	while(*str!=0x00)
	{
		UartPutc(*str);
		str++;
	}
}
const char Dec2Ascii[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
void UartPut2x(unsigned char ddd)
{
	UartPutc(Dec2Ascii[(ddd>>4)&0x0f]);
	UartPutc(Dec2Ascii[ddd&0x0f]);
}
void UartPut4x(unsigned short ddd)
{
	UartPutc(Dec2Ascii[(ddd>>12)&0x0f]);
	UartPutc(Dec2Ascii[(ddd>>8)&0x0f]);
	UartPutc(Dec2Ascii[(ddd>>4)&0x0f]);
	UartPutc(Dec2Ascii[ddd&0x0f]);
}
void UartPut8x(unsigned int ddd)
{
	UartPut4x(ddd>>16);
	UartPut4x(ddd);
}
void UartPut4d(unsigned short ddd)
{
	UartPutc(Dec2Ascii[(ddd/1000)%10]);
	UartPutc(Dec2Ascii[(ddd/100)%10]);
	UartPutc(Dec2Ascii[(ddd/10)%10]);
	UartPutc(Dec2Ascii[ddd%10]);
}
void SetupPA15(void)
{
#ifdef ENABLE_K6_PA15	
	GPIO_InitTypeDef GPIO_InitStructure;	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
		
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  //GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//because Open Drain need pull up resistor
  GPIO_Init(GPIOA, &GPIO_InitStructure);	
#else	
	GPIO_InitTypeDef GPIO_InitStructure;	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOF, ENABLE);
		
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  //GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//because Open Drain need pull up resistor
  GPIO_Init(GPIOF, &GPIO_InitStructure);
#endif
}
void SetupI2CAAA(void)
{
 // enable clock for used IO pins
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

  // I2C1 : SCL = 17:PA9, SDA = 18:PA10
  GPIO_InitTypeDef GPIO_InitStruct;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_OType = GPIO_OType_OD; // Open Drain
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOA, &GPIO_InitStruct);

  GPIO_PinAFConfig(GPIOA, GPIO_PinSource9 , GPIO_AF_4); // 17:PA9  = AF4/I2C1_SCL
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_4); // 18:PA10 = AF4/I2C1_SDA

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

  I2C_DeInit(I2C1); //Deinit and reset the I2C to avoid it locking up
  I2C_SoftwareResetCmd(I2C1);

  // Init I2C1
  I2C_InitTypeDef  I2C_InitStructure;

  /* Configure the I2C clock source. The clock is derived from the HSI */
  RCC_I2CCLKConfig(RCC_I2C1CLK_HSI);

  I2C_Cmd(I2C1, ENABLE);
	
	//I2C_StretchClockCmd(I2C1,ENABLE);//Dollar
	//I2C_SlaveByteControlCmd(I2C1,ENABLE);//Dollar
	//I2C_NumberOfBytesConfig(I2C1,1);//Dollar
	//I2C_ReloadCmd(I2C1,ENABLE);//Dollar

  /*!< I2C configuration */
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
  I2C_InitStructure.I2C_AnalogFilter = I2C_AnalogFilter_Enable;
  I2C_InitStructure.I2C_DigitalFilter = 0x00;
  I2C_InitStructure.I2C_OwnAddress1 = (0x18<<1) ;
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitStructure.I2C_Timing = 0x00200000;//0x00900000???

  /* Apply I2C configuration after enabling it */
  I2C_Init(I2C1, &I2C_InitStructure);

  // Interrupted I2C1
  NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_InitStructure.NVIC_IRQChannel = I2C1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  I2C_ITConfig(I2C1, I2C_IT_TCR | I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_STOPI | I2C_IT_NACKI | I2C_IT_ADDRI | I2C_IT_RXI | I2C_IT_TXI, ENABLE);
}
static void SetSysClockHSI(void)	
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;	
	
  /* Set HSION bit */
  RCC->CR |= (uint32_t)0x00000001;

  /* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE and MCOSEL[2:0] bits */
  RCC->CFGR &= (uint32_t)0xF8FFB80C;
  
  /* Reset HSEON, CSSON and PLLON bits */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* Reset HSEBYP bit */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* Reset PLLSRC, PLLXTPRE and PLLMUL[3:0] bits */
  RCC->CFGR &= (uint32_t)0xFFC0FFFF;

  /* Reset PREDIV1[3:0] bits */
  RCC->CFGR2 &= (uint32_t)0xFFFFFFF0;

  /* Reset USARTSW[1:0], I2CSW, CECSW and ADCSW bits */
  RCC->CFGR3 &= (uint32_t)0xFFFFFEAC;

  /* Reset HSI14 bit */
  RCC->CR2 &= (uint32_t)0xFFFFFFFE;

  /* Disable all interrupts */
  RCC->CIR = 0x00000000;
//	

  RCC_HSICmd(ENABLE);

  /* Wait till LSI is ready */  
  while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET)
  {
  }
  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSIRDY;//RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSI_STARTUP_TIMEOUT));//HSE_STARTUP_TIMEOUT

  if ((RCC->CR & RCC_CR_HSIRDY) != RESET)//RCC_CR_HSERDY
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  

  if (HSEStatus == (uint32_t)0x01)
  {
    /* Enable Prefetch Buffer and set Flash Latency */
    FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY;
 
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1;

    /* PLL configuration */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
   // RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL6);
	 RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI_Div2 | RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLMULL12);//48MHz
	 
    /* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }

    /* Select PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* Wait till PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)
    {
    }
  }
  else
  { /* If HSE fails to start-up, the application will have wrong clock 
         configuration. User can add here some code to deal with this error */
				 while(1)
				 {
					 
				 }
  }  	

} 
typedef  void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t JumpAddress;
//extern pFunction Jump_To_Application;
//extern uint32_t JumpAddress;
void delay(void)
{
	unsigned short i;
	for(i=0;i<0xfff0;i++)
	{
		//
	}
}
void GotoUserCode(void)
{
#ifdef ENABLE_K6_PA15	
	if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)==Bit_SET)//Normal High
#else	
	if(GPIO_ReadInputDataBit(GPIOF,GPIO_Pin_0)==Bit_SET)
#endif	
	{
		UartPuts("\r\n@ Pin Hi,Goto User\r\n");
		
		delay();
		
		//default goto User code.	
		/* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */
		if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)
		{
			//UartPuts("\r\nUser Code Ok!\r\n");
			
			/* Jump to user application */
			JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);
			Jump_To_Application = (pFunction) JumpAddress;
			
			/* Initialize user application's Stack Pointer */
			__set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);
			
			/* Jump to application */
			Jump_To_Application();
		}		
		UartPuts("\r\n@ User Code Bad!");
	}
	else
	{
		UartPuts("\r\n@ Pin Low,Goto BL\r\n");
	}	
}
int main(void)
{
	//char ccc;
	SetSysClockHSI();
	
	SystemCoreClockUpdate ();
	
  if (SysTick_Config(SystemCoreClock / 100))//10ms
  { 
    /* Capture error */ 
    while (1);
  }
	
	SetupI2CAAA();
	UART_ConfigPA23();
	SetupPA15();
	
	ChkUartRx();
	#ifdef ENABLE_K6_PA15
		UartPuts("\r\n@ BL PA15 0516b=");
	#else
		//UartPuts("\r\n@ BL PF0 0618=");
		UartPuts("\r\n@ BL PF0 0806=");
	#endif
	UartPut8x((unsigned int)main);
	//UartPuts("\r\n");
	
	GotoUserCode();
	
  /* Infinite loop */
	PreCounter=NowCounter;//update timer
  while (1)
  {
		ChkUartRx();
		
		if(GetAbsTime(NowCounter,PreCounter)>=100)//10*100ms=1sec
		{
			UartPutc('b');
			
			//10ms
			PreCounter=NowCounter;//update timer

		}
  }
}
//===========================================
extern uint8_t DataRx[];//MTK tx to MCU.
extern uint8_t DataTx[];//MCU tx to MTK.

unsigned int u32addr;
unsigned short u16size;
uint32_t u32tmp;
//
#define RD_VER			 		(0x92)
//
#define RD_USER_FLASH	 	(0x03)
#define WR_USER_FLASH  	(0x06)
#define ER_USER_FLASH	 	(0x60)
//
#define BL_GOTO_USER 		(0x77)
//

void WriteCallBackToMCU(unsigned char cnt)
{
	unsigned int i;
	unsigned char* u8ptr;
	
	if(cnt<8)
	{
	UartPut2x(DataRx[cnt]);
	UartPutc(',');
	}
	
	if(cnt==(8-1))//first 8 Byte
	{
		u32addr=(DataRx[1]<<24|DataRx[2]<<16|DataRx[3]<<8|DataRx[4]);
		u16size=(DataRx[5]<<8|DataRx[6]);
		
		//printf("addr=%x,size=%x\r\n",u32addr,u16size);
		
		if(DataRx[7]!=0xff)
		{
			//dummy byte
			//printf("Byte7=%x\r\n",DataRx[7]);
		}
		
		if(DataRx[0]==RD_USER_FLASH)
		{
			
			if(u16size>128)											u16size=128;		
			
			//printf("\r\nRd 0x%x,Sz=%x\r\n",u32addr,u16size);//debug	
			
			u8ptr=(unsigned char *)(u32addr);
			for(i=0;i<u16size;i++)
			{
					DataTx[i] = *u8ptr ;
					//printf("%2x",DataTx[i]);//debug	
					u8ptr++;
			}		
			//printf("\r\n");//debug	
				
		}
		else if(DataRx[0]==ER_USER_FLASH)
		{
			FLASH_Unlock();
			/* Clear All pending flags */
			FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR);
			/* Erase the FLASH pages */

			for(i=APPLICATION_ADDRESS;i<(APPLICATION_ADDRESS_END);i=i+PAGE_SIZE)
			{
				//printf("\r\nEr 0x%x",(i));	
				FLASH_ErasePage(i);//1KB.
			}
			FLASH_Lock();			
			
			UartPutc('e');
		}	
		else if(DataRx[0]==RD_VER)
		{
					//F/w Version
					DataTx[0]=BL_FW_VERSION>>8;
					DataTx[1]=BL_FW_VERSION&0xff;
					DataTx[2]=0x01;//1:Bootloader,2:User Code
					DataTx[3]=0x00;
					DataTx[4]=0x00;
					DataTx[5]=0x00;
					DataTx[6]=0x55;
					DataTx[7]=0x55;				
		}
		else if(DataRx[0]==BL_GOTO_USER)
		{
				GotoUserCode();
		}
		else
		{
			//printf("Unknow cmd=%x\r\n",DataRx[0]);
		}
	}
	//else if(cnt>=(32+8-1))//32B
	else if(cnt>=(u16size+(8-1)))//0x34+8B
	{
		if(DataRx[0]==WR_USER_FLASH)
		{
			if(u16size>128)	u16size=128;
			
			if(u32addr<APPLICATION_ADDRESS)					
			{
				//can't re-write other Area
				UartPutc('?');
				return;	
			}
			if(u32addr>APPLICATION_ADDRESS_END)
			{
				//can't re-write other Area
				UartPutc('?');
				return;	
			}
			
				//write 32bit:
				FLASH_Unlock();
				/* Clear pending flags (if any) */  
				FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPERR); 
				
				//at least 4B every program:
				u16size+=3;
				u16size&=0xfffc;				
				
				//printf("\r\nPgr 0x%x,Sz=%x\r\n",u32addr,u16size);//debug	
				
				for (i=0; i<(u16size); i=i+4)
				{
						//remove command header and become 32bit prog.
						u32tmp=0;
						u32tmp|=(DataRx[i+(8+0)]<<0);
						u32tmp|=(DataRx[i+(8+1)]<<8);
						u32tmp|=(DataRx[i+(8+2)]<<16);
						u32tmp|=(DataRx[i+(8+3)]<<24);
						
						//printf("%4x",u32tmp);//debug	
					 
						FLASH_ProgramWord(u32addr+i,u32tmp);
				}
				//printf("\r\n");
				FLASH_Lock();					
				
				UartPutc('p');
		}		
	}
	
}


#ifdef  USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{ 
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
